﻿using System;
using System.Collections.ObjectModel;
using System.Threading;
using System.Windows.Threading;
using DataStore;
using DataStore.Domain;
using DataStore.Repositories;
using Infrastructure.CurrentData;
using log4net;
using Microsoft.Practices.Composite.Events;

namespace Infrastructure.ViewModels
{
    /// <summary>
    /// AllKeywords viewmodel
    /// </summary>
    public class AllKeywordsViewModel : DataModel
    {
        ObservableCollection<KeywordViewModel> _keywords = new ObservableCollection<KeywordViewModel>();

        /// <summary>
        /// Initializes a new instance of the <see cref="AllKeywordsViewModel"/> class.
        /// </summary>
        public AllKeywordsViewModel() : base()
        {
            Initialize();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="AllKeywordsViewModel"/> class.
        /// </summary>
        public AllKeywordsViewModel(IEventAggregator eventAggregator) : base(eventAggregator)
        {
            Initialize();
        }

        /// <summary>
        /// Initializes this instance.
        /// </summary>
        void Initialize()
        {

            State = ModelState.Fetching;

            RefreshKeywords();
        }

        /// <summary>
        /// Refreshes the keywords.
        /// </summary>
        void RefreshKeywords()
        {
            Log.Debug("Refreshing keywords");

            if (!ThreadPool.QueueUserWorkItem(FetchKeywordsCallback))
            {
                State = ModelState.Invalid;
            }
        }

        /// <summary>
        /// Gets or sets the keywords.
        /// </summary>
        /// <value>The keywords.</value>
        public ObservableCollection<KeywordViewModel> Keywords
        {
            get
            {
                VerifyCalledOnUIThread();
                return _keywords;
            } 
            set
            {
                VerifyCalledOnUIThread();
                if (_keywords != value)
                {
                    _keywords = value;
                    OnPropertyChanged("Keywords");
                }
            }
        }

        /// <summary>
        /// Fetches the keywords from data store.
        /// </summary>
        /// <param name="state">The state.</param>
        void FetchKeywordsCallback(object state)
        {
            Log.Debug("Fetching keywords from database");

            IDatabase database = Current.Container.Resolve<IDatabase>();
            var unitOfWork = database.CreateUnitOfWork();
            IRepository<Keyword> repository = new KeywordRepository(unitOfWork);

            try
            {
                var keywords = repository.All;

                Dispatcher.BeginInvoke(
                    new ThreadStart(delegate
                                        {
                                            Keywords.Clear();
                                            foreach (var keyword in keywords)
                                            {
                                                Keywords.Add(new KeywordViewModel(EventAggregator, keyword));
                                            }

                                            unitOfWork.Dispose();

                                            State = ModelState.Active;
                                            OnLoaded(this, EventArgs.Empty);
                                        }),
                    DispatcherPriority.ApplicationIdle);
            }
            catch (Exception e)
            {
                Log.Error("Failed to load Keywords", e);

                unitOfWork.Dispose();
                Dispatcher.BeginInvoke(
                    new ThreadStart(delegate
                                        {
                                            State = ModelState.Invalid;
                                            OnLoaded(this, EventArgs.Empty);
                                        }),
                    DispatcherPriority.ApplicationIdle);

            }
        }
    }
}